﻿%{
    // Эти объявления добавляются в класс Parser, представляющий собой парсер, генерируемый системой gppg
	
    public ProgramNode root; // Корневой узел синтаксического дерева 
	
	/// Вспомогательные инструменты парсера
	private ParserToolsManager toolsManager;
	/// Вспомогательные инструменты парсера
	public ParserToolsManager ToolsManager
	{
		get { return toolsManager; }
	}
	
    public Parser(ConceptsParser.Scanner.Scanner scanner) : base(scanner) 
	{ 
		toolsManager = scanner.ToolsManager;
	}
%}

%output = ..\ConceptsYacc.cs

%using System.IO;

%using ConceptsParser.SyntaxTree;
%using ConceptsParser.ParserTools;

%namespace ConceptsParser.Parser


/* **************************************** Типы ***************************************** */

%union { 
    public string sVal;                           	// Строковый тип
    
    public ConceptsSyntaxTreeNode nVal;
    public ProgramNode prVal;                      	// Вся программа
    
    public UsingSectionNode useSecVal;
    public ConceptsSectionNode cnptSecVal;
    
    public QualifiedNamespaceNode qNamespVal;
    public LinkedList<string> dListSVal;
    public TypeArgumentNode typeArgVal;
    public LinkedList<TypeArgumentNode> dListTypeArgVal;
    public TypeQualifierNode typeQualfVal;
    public LinkedList<TypeQualifierNode> dListTypeQualfVal;
    
    public UsingDirectiveNode useDirVal;
    
    public ConceptDefinitionNode cnptDefVal;
    public ConceptSignatureNode cnptSigVal;
    public ConceptBodyNode cnptBodyVal;
    public InnerConceptDeclarationNode cnptDeclVal;
    public LinkedList<InnerConceptDeclarationNode> dListCnptDeclVal;
    public ConceptReferenceNode cnptRefVal;
    public TypeConstraintOperator cnstrOpVal;
    public InnerConceptRequirementNode cnptReqVal;
    public InnerConceptAliasNode cnptAliasVal;
    public ConstraintOnTypeArgNode cnstrOnTypeVal;
}
       

%start program                                                // Стартовый символ — программа, файл с кодом

/* *************************************** Токены **************************************** */

%token <sVal> ID

// ================================= Ключевые слова

%token CONCEPT REFINES EXPLICIT
%token USING
%token REQUIRE TYPE

// ================================= Разделители

%token LBRACE RBRACE
%token ASSIGN
%token <cnstrOpVal> EQUAL SUBTYPE SUPERTYPE
%token LBRACKET RBRACKET
%token LANGLE RANGLE
%token SEMICOLON POINT COMMA

// ================================= Нетерминалы

%type <prVal> ConceptsProgram
%type <useSecVal> UsingSection
%type <cnptSecVal> ConceptSection

%type <qNamespVal> QualifiedNamespace
%type <sVal> NamespaceQualifierItem
%type <dListSVal> NamespaceQualifier TypeParams
%type <typeArgVal> TypeArgument TypeItem
%type <dListTypeArgVal> TypeArguments
%type <dListTypeQualfVal> TypeQualifier
%type <typeQualfVal> TypeQualifierItem

%type <useDirVal> UsingDirective
    
%type <cnptDefVal> ConceptDefinition AnyConceptDefinition
%type <cnptSigVal> ConceptSignature RefinementDeclaration
%type <cnptBodyVal> ConceptBody
%type <dListCnptDeclVal> ConceptDeclarations
%type <cnptDeclVal> InnerConceptDeclaration
%type <cnstrOpVal> TypeConstraintBinOperator
%type <cnptRefVal> ConceptReference
%type <cnptReqVal> NestedConceptRequirement AssociatedTypeDeclaration TypeConstraintDeclaration
%type <sVal> NestedConceptAlias
%type <cnstrOnTypeVal> TypeConstraint
%type <cnptAliasVal> ConceptAlias TypeAlias
    

%%

/* ************************************* Нетерминалы ************************************* */

// ================================= Основные блоки

program : ConceptsProgram {
        root = $1;
    }
    ;

ConceptsProgram
    : UsingSection ConceptSection { 
        $$ = new ProgramNode(@$, $1, $2);
    }
    ;

// ================================= Идентификаторы

QualifiedNamespace
    : ID {
        $$ = new QualifiedNamespaceNode(@$, $1);
    }
    | NamespaceQualifier ID {
        $1.AddLast($2);
        $$ = new QualifiedNamespaceNode(@$, $1);
    }
    ;

NamespaceQualifierItem
    : ID POINT {
        $$ = $1;
    }
    ;
    
NamespaceQualifier
    : NamespaceQualifierItem {
        $$ = new LinkedList<string>();
        $$.AddLast($1);
    }
    | NamespaceQualifier NamespaceQualifierItem {
        $$ = $1;
        $$.AddLast($2);
    }
    ;
    
TypeParams
    : ID {
        $$ = new LinkedList<string>();
        $$.AddLast($1);
    }
    | TypeParams COMMA ID {
        $$ = $1;
        $$.AddLast($3);
    }
    ;
    
TypeArguments
    : TypeArgument {
        $$ = new LinkedList<TypeArgumentNode>();
        $$.AddLast($1);
    }
    | TypeArguments COMMA TypeArgument {
        $$ = $1;
        $$.AddLast($3);
    }
    ;
    
TypeArgument
    : TypeItem {
        $$ = $1;
    }
    | TypeQualifier TypeItem {
        $$ = $2;
        $$.SetQualifier($1);
        $$.SetNewLocation(@$);
    }
    ;
    
TypeItem 
    : ID {
        $$ = new SimpleTypeArgumentNode(@$, $1);
    }
    | ID LANGLE TypeArguments RANGLE {
        $$ = new GenericTypeArgumentNode(@$, $1, $3);
    }
    ;

TypeQualifier
    : TypeQualifierItem POINT {
        $$ = new LinkedList<TypeQualifierNode>();
        $$.AddLast($1);
    }
    | TypeQualifier TypeQualifierItem POINT {
        $$ = $1;
        $$.AddLast($2);
    }
    ;
    
TypeQualifierItem
    : ID {
        $$ = new IDTypeQualifierNode(@$, $1);
    }
    | ConceptReference {
        $$ = new ConceptReferenceQualifierNode(@$, $1);
    }
    ;
    

// ================================= Секция using

UsingSection
    : UsingSection UsingDirective {
        $$ = $1;
        $$.AddUsingDirective($2);
        $$.SetNewLocation(@$);
    }
    | {
        $$ = new UsingSectionNode(@$);
    }
    ;
    
UsingDirective
    : USING QualifiedNamespace SEMICOLON {
        $$ = new UsingDirectiveNode(@$, $2);
    }
    ;

// ================================= Секция концептов

ConceptSection
    : ConceptSection AnyConceptDefinition {
        $$ = $1;
        $$.AddConceptDefinition($2);
        $$.SetNewLocation(@$);
    }
    | {
        $$ = new ConceptsSectionNode(@$);
    }
    ;

AnyConceptDefinition
    : ConceptDefinition {
        $$ = $1;
    }
    | EXPLICIT ConceptDefinition {
        $$ = $2;
        $$.IsExplicit = true;
        $$.SetNewLocation(@$);
    }
    ;
    
ConceptDefinition 
    : CONCEPT ConceptSignature RefinementDeclaration LBRACE ConceptBody RBRACE {
        $$ = new ConceptDefinitionNode(@$, $2, $3, $5);
    }
    ;
    
ConceptSignature
    : ID LBRACKET TypeParams RBRACKET {
        $$ = new ConceptSignatureNode(@$, $1, $3);
    }
    ;
    
RefinementDeclaration
    : REFINES ConceptSignature {
        $$ = $2;
    }
    | {
        $$ = null;
    }
    ;
    
ConceptBody
    : ConceptDeclarations {
        $$ = new ConceptBodyNode(@$, $1);
    }
    ;
    
ConceptDeclarations
    : ConceptDeclarations InnerConceptDeclaration {
        $$ = $1;
        $$.AddLast($2);
    }
    | {
        $$ = new LinkedList<InnerConceptDeclarationNode>();
    }
    ;

InnerConceptDeclaration
    : NestedConceptRequirement {
        $$ = $1;
    }
    | AssociatedTypeDeclaration {
        $$ = $1;
    }
    | TypeConstraintDeclaration {
        $$ = $1;
    }
    | ConceptAlias {
        $$ = $1;
    }
    | TypeAlias {
        $$ = $1;
    }
    ;
    
NestedConceptRequirement
    : REQUIRE ConceptReference NestedConceptAlias SEMICOLON {
        $$ = new NestedConceptRequirementNode(@$, $2, $3);
    }
    ;
    
NestedConceptAlias
    : USING ID {
        $$ = $2;
    }
    | {
        $$ = null;
    }
    ;
    
ConceptReference
    : ID LBRACKET TypeArguments RBRACKET {
        $$ = new ConceptReferenceNode(@$, $1, $3);
    }
    ;
    
TypeConstraintBinOperator
    : EQUAL {
        $$ = TypeConstraintOperator.EQUAL;
    }
    | SUBTYPE {
        $$ = TypeConstraintOperator.SUBTYPE;
    }
    | SUPERTYPE {
        $$ = TypeConstraintOperator.SUPERTYPE;
    }
    ;
    
AssociatedTypeDeclaration
    : TYPE ID TypeConstraint SEMICOLON {
        $$ = new AssociatedTypeDeclarationNode(@$, $2, $3);
    }
    ;

TypeConstraint
    : TypeConstraintBinOperator TypeArgument {
        $$ = new ConstraintOnTypeArgNode(@$, $2, $1);
    }
    | {
        $$ = null;
    }
    ;
    
TypeConstraintDeclaration
    : REQUIRE TypeArgument TypeConstraintBinOperator TypeArgument SEMICOLON {
        $$ = new TypeRequirementNode(@$, $2, $4, $3);
    }
    ;
    
ConceptAlias
    : USING ID ASSIGN ConceptReference SEMICOLON {
        $$ = new ConceptAliasNode(@$, $2, $4);
    }
    ;
   
TypeAlias
    : USING ID ASSIGN TypeArgument SEMICOLON {
        $$ = new TypeAliasNode(@$, $2, $4);
    }
    ;